#include <ssh/server.h>
#include <ssh/client.h>
#include <libssh/server.h>
#include <fort.h>
#include <libssh/callbacks.h>
#include <sys/stat.h>
#include <thread>
using namespace fort;

SSHServer::SSHServer() : sshbind(nullptr)
{

    if (ssh_init() < 0) {
        fprintf(stderr, "ssh_init failed\n");
        this->sshbind = nullptr;
        return ;
    }
    sshbind = ssh_bind_new();
    ssh_bind_options_set(this->sshbind, SSH_BIND_OPTIONS_BINDADDR, this->host.c_str());
    ssh_bind_options_set(this->sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, this->port.c_str());
    ssh_bind_options_set(this->sshbind, SSH_BIND_OPTIONS_RSAKEY, this->rsa_key.c_str());
    ssh_bind_options_set(this->sshbind, SSH_BIND_OPTIONS_HOSTKEY, this->host_key.c_str());
    if (ssh_bind_listen(this->sshbind) < 0)
    {
        printf("Error listening to socket: %s\n", ssh_get_error(this->sshbind));
        this->sshbind = nullptr;
        return;
    }
    /**初始化事件类*/
    this->ep = new EpollSSHEvent();
    bool stat = this->ep->init();
    if(stat){
        ep->run();
    }
}

void SSHServer::call_handel(SSHServer *ss, ssh_session session){
    ss->handel(session);
}

void SSHServer::accept()
{
    if (sshbind != nullptr)
        while (1)
        {
            ssh_session session = ssh_new();
            if (ssh_bind_accept(this->sshbind, session) != SSH_ERROR)
            {
                thread t(call_handel,this,session);
                t.detach();
                continue;
            }
            cout << "accept" << endl; 
            ssh_free(session); 
        }
}

void SSHServer::handel(ssh_session session)
{
    ssh_event event = ssh_event_new();
    SSHFort *sdata = new SSHFort();
    sdata->evnet = ep;
    sdata->poll_event = event;
    struct ssh_server_callbacks_struct *server_cb = new ssh_server_callbacks_struct;
    server_cb->userdata = sdata;
    server_cb->auth_password_function = auth_pass;
    server_cb->auth_none_function = auth_none_callback;
    server_cb->auth_pubkey_function = auth_pubkey;
    server_cb->service_request_function = request_callback;
    server_cb->channel_open_request_session_function = open_channel; 

    ssh_callbacks_init(server_cb);
    sdata->server_callbacks = server_cb;
    ssh_set_server_callbacks(session, server_cb);
    ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
    if (ssh_handle_key_exchange(session) != SSH_OK)
    {
        printf("Error performing key exchange: %s\n", ssh_get_error(session));
        return;
    }
    ssh_event_add_session(event, session);
    int n = 0;
    while ((sdata->flag & PASSWORD_PASS) == 0 || ( sdata->client == nullptr || sdata->client->channel == NULL ))
    {
        if ((sdata->flag & PASSWORD_ERROR_NUMBER) >= 3 || n >= 100)
        {
            delete(sdata);
            return;
        }
        if (ssh_event_dopoll(event, 500) == SSH_ERROR)
        {
            if(sdata->client != nullptr){
                delete(sdata);
            }
            fprintf(stderr, "%s\n", ssh_get_error(session));
            return;
        }
        if(sdata->flag & CHANNEL_ERROR){
            delete(sdata);
            cout << "outher error !" << endl ;
        }
        n++;
    }
}

